package org.jsola.hr.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.jsola.common.ArrayKit;
import org.jsola.common.StrKit;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.BeanCopyUtil;
import org.jsola.hr.common.ListKit;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dto.NoticeRuleSettingDTO;
import org.jsola.hr.entity.CompanyDO;
import org.jsola.hr.provider.INoticeProviderService;
import org.jsola.hr.provider.IUserProviderService;
import org.jsola.hr.service.IChannelService;
import org.jsola.hr.service.ICompanyService;
import org.jsola.hr.service.INoticeService;
import org.jsola.hr.vo.*;
import org.jsola.notice.constant.EmpType;
import org.jsola.notice.constant.NoticeConstants;
import org.jsola.notice.constant.ReceiveDateTypeEnum;
import org.jsola.notice.constant.WayType;
import org.jsola.notice.dto.NoticeRuleSettingAddDTO;
import org.jsola.notice.dto.NoticeRuleSettingUpdateDTO;
import org.jsola.notice.entity.NoticeGroupDO;
import org.jsola.notice.entity.NoticeRuleSettingDO;
import org.jsola.notice.service.INoticeRuleSettingService;
import org.jsola.notice.vo.NoticeDateSettingVO;
import org.jsola.notice.vo.NoticeGroupListVO;
import org.jsola.notice.vo.NoticeRuleSettingVO;
import org.jsola.notice.vo.NoticeTypeVO;
import org.jsola.user.core.TokenUser;
import org.jsola.user.entity.UserDO;
import org.jsola.user.vo.UserVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

import static org.jsola.hr.constant.HrConstants.*;

/**
 * @author wcl
 */
@Slf4j
@Service("hrNoticeServiceImpl")
public class NoticeServiceImpl implements INoticeService {

    @Autowired
    private INoticeProviderService noticeProviderService;

    @Autowired
    private IUserProviderService userProviderService;

    @Autowired
    private ICompanyService companyService;

    @Autowired
    private IChannelService channelService;

    @Autowired
    private INoticeRuleSettingService noticeRuleSettingService;

    @Override
    public List<HrNoticeGroupListVO> listAllByCompanyId(String companyId, TokenUser tokenUser) {
        List<NoticeGroupListVO> noticeGroupListVOS = noticeProviderService.listAllByCompanyId(companyId, HrConstants.HR_SUBJECT_TYPE, tokenUser);
        if (CollectionUtils.isEmpty(noticeGroupListVOS)) {
            return new ArrayList<>();
        }
        List<HrNoticeGroupListVO> hrNoticeGroupListVOS = noticeGroupListVOS.stream()
                .map(s -> BeanCopyUtil.beanCopy(s, HrNoticeGroupListVO.class))
                .collect(Collectors.toList());

        for (HrNoticeGroupListVO hrNoticeGroupListVO : hrNoticeGroupListVOS) {
            List<HrNoticeTypeListVO> noticeTypeList = hrNoticeGroupListVO.getNoticeTypeList();
            if (CollectionUtils.isEmpty(noticeTypeList)) {
                continue;
            }
            // 根据sort排序
            List<HrNoticeTypeListVO> sortCollect = hrNoticeGroupListVO.getNoticeTypeList().parallelStream()
                    .sorted(Comparator.comparing(HrNoticeTypeListVO::getSort))
                    .collect(Collectors.toList());
            hrNoticeGroupListVO.setNoticeTypeList(sortCollect);
            for (HrNoticeTypeListVO hrNoticeTypeListVO : noticeTypeList) {
                HrNoticeRuleSettingListVO hrNoticeRuleSettingListVO = hrNoticeTypeListVO.getNoticeRuleSettingListVO();
                if (Objects.nonNull(hrNoticeRuleSettingListVO)) {
                    HrNoticeUserIdJsonVO hrNoticeUserIdJsonVO = JSONObject.parseObject(hrNoticeRuleSettingListVO.getUserIdParam(), HrNoticeUserIdJsonVO.class);
                    if (hrNoticeUserIdJsonVO != null) {
                        hrNoticeRuleSettingListVO.setHrNoticeUserIdJsonVO(hrNoticeUserIdJsonVO);
                        // 用户id
                        String userIds = hrNoticeUserIdJsonVO.getUserIds();
                        if (StringUtil.isNotBlank(userIds)) {
                            List<String> userIdList = ListKit.stringToList(userIds);
                            List<UserDO> userDOList = userProviderService.selectUserByIds(userIdList);
                            List<UserVO> userVOList = new ArrayList<>();
                            if (!CollectionUtils.isEmpty(userDOList)) {
                                userVOList = userDOList.stream()
                                        .map(userDO -> userDO.to(UserVO.class))
                                        .collect(Collectors.toList());
                            }
                            if (!CollectionUtils.isEmpty(userVOList)) {
                                hrNoticeRuleSettingListVO.setUserVOList(userVOList);
                            }
                        }
                    }
                    String dateJson = hrNoticeRuleSettingListVO.getReceiveDateJson();
                    HrNoticeDateSettingVO dateSettingVO = parse(dateJson);
                    hrNoticeRuleSettingListVO.setHrNoticeDateSettingVO(dateSettingVO);
                }
            }
        }
        return hrNoticeGroupListVOS;
    }

    @Override
    public List<HrNoticeGroupListVO> listAllGroup(TokenUser tokenUser) {
        List<NoticeGroupListVO> noticeGroupListVOS = noticeProviderService.listAll(HrConstants.HR_SUBJECT_TYPE);
        List<HrNoticeGroupListVO> hrNoticeGroupListVOList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(noticeGroupListVOS)) {
            hrNoticeGroupListVOList = noticeGroupListVOS.stream()
                    .map(s -> s.to(HrNoticeGroupListVO.class))
                    .collect(Collectors.toList());
        }
        return hrNoticeGroupListVOList;
    }

    @Override
    public void saveOrUpdateNoticeRuleSetting(NoticeRuleSettingDTO noticeRuleSettingDTO, TokenUser tokenUser) {

        String channelIds = noticeRuleSettingDTO.getChannelIds();
        String userIds = noticeRuleSettingDTO.getUserIds();

        // 写入渠道的userId
        List<String> channelIdList = ArrayKit.split(channelIds, ",");
        List<ChannelVO> channelVOS = channelService.selectByIds(channelIdList, tokenUser.getSiteId());
        List<String> channelUserIdList = new ArrayList<>();
        for (ChannelVO channelVO : channelVOS) {
            String phone = channelVO.getPhone();
            if (StrKit.isNotEmpty(phone)) {
                UserDO userDO = userProviderService.selectByPhone(phone);
                if (userDO != null) {
                    channelUserIdList.add(userDO.getId());
                }
            }
        }
        String channelUserIds = String.join(",", channelUserIdList);
        HrNoticeUserIdJsonVO hrNoticeUserIdJsonVO = new HrNoticeUserIdJsonVO();
        hrNoticeUserIdJsonVO.setChannelUserIds(channelUserIds);
        hrNoticeUserIdJsonVO.setChannelIds(channelIds);
        hrNoticeUserIdJsonVO.setUserIds(userIds);

        noticeRuleSettingDTO.setUserIdParam(JSON.toJSONString(hrNoticeUserIdJsonVO));
        ParamException.hasText(noticeRuleSettingDTO.getReceiveType(), "请选择接收方式");
        if (null == noticeRuleSettingDTO.getId()) {
            noticeProviderService.save(noticeRuleSettingDTO.to(NoticeRuleSettingAddDTO.class), tokenUser);
        } else {
            noticeProviderService.update(noticeRuleSettingDTO.to(NoticeRuleSettingUpdateDTO.class), tokenUser);
        }
    }

    /**
     * 解析通知时间规则
     *
     * @param dateJson
     */
    private HrNoticeDateSettingVO parse(String dateJson) {
        return JSON.parseObject(dateJson, HrNoticeDateSettingVO.class);
    }

    @Override
    public int openNoticeRuleSetting(Long id, TokenUser tokenUser) {
        return noticeProviderService.openNoticeRuleSetting(id, tokenUser);
    }

    @Override
    public int closeNoticeRuleSetting(Long id, TokenUser tokenUser) {
        return noticeProviderService.closeNoticeRuleSetting(id, tokenUser);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public Integer initAllCompany(TokenUser tokenUser) {
        int count = 0;
        List<CompanyDO> companyDOList = companyService.selectAll();
        log.info("==========用工单位规则设置初始化开始==========");
        log.info("共{}个用工单位", companyDOList.size());
        long startTime = System.currentTimeMillis();
        // 查询所有分组
        List<NoticeGroupListVO> noticeGroupVOList = noticeProviderService.listAll(HrConstants.HR_SUBJECT_TYPE);

        // 循环用工单位
        for (CompanyDO companyDO : companyDOList) {
            String companyId = companyDO.getId();

            // 循环通知分组
            for (NoticeGroupListVO noticeGroupListVO : noticeGroupVOList) {
                Long noticeGroupId = noticeGroupListVO.getId();
                // 查询分组下所有分类
                List<NoticeTypeVO> noticeTypeVOList = noticeProviderService.listTypeByGroupId(HrConstants.HR_SUBJECT_TYPE, noticeGroupId);

                // 循环通知分类
                for (NoticeTypeVO noticeTypeVO : noticeTypeVOList) {
                    Long noticeTypeId = noticeTypeVO.getId();
                    // 查询公司通知规则设置,不存在则创建
                    NoticeRuleSettingVO noticeRuleSettingVO = noticeProviderService.selectByTypeCodeAndCompany(HrConstants.HR_SUBJECT_TYPE, noticeTypeId, companyId);
                    if (null == noticeRuleSettingVO) {
                        // 初始化通知规则
                        tokenUser.setSiteId(companyDO.getSiteId());
                        NoticeRuleSettingAddDTO noticeRuleSettingAddDTO = new NoticeRuleSettingAddDTO();
                        noticeRuleSettingAddDTO.setCompanyId(companyId);
                        noticeRuleSettingAddDTO.setEmpType(EmpType.CUSTOM.getValue());
                        noticeRuleSettingAddDTO.setUserIds(null);
                        noticeRuleSettingAddDTO.setModuleType(HrConstants.HR_SUBJECT_TYPE);
                        noticeRuleSettingAddDTO.setNoticeTypeId(noticeTypeId);
                        noticeRuleSettingAddDTO.setNoticeTypeCode(noticeTypeVO.getCode());
                        noticeRuleSettingAddDTO.setEnableStatus(false);
                        noticeRuleSettingAddDTO.setReceiveType(WayType.WEIXIN.getValue());
                        if (NoticeConstants.TURN_OFFICIAL.equals(noticeTypeVO.getCode())
                                || NoticeConstants.TRANSFER.equals(noticeTypeVO.getCode())
                                || NoticeConstants.RESIGN.equals(noticeTypeVO.getCode())
                                || NoticeConstants.INDUCTION.equals(noticeTypeVO.getCode())) {
                            // 前1天
                            noticeRuleSettingAddDTO.setReceiveDateType(ReceiveDateTypeEnum.BEFORE.getValue());
                            NoticeDateSettingVO settingVO = new NoticeDateSettingVO();
                            settingVO.setNumber(1);
                            settingVO.setUnit(3);
                            String jsonDate = JSON.toJSONString(settingVO);
                            noticeRuleSettingAddDTO.setReceiveDateJson(jsonDate);

                        } else if (NoticeConstants.CONTRACT_EXPIRES.equals(noticeTypeVO.getCode())) {
                            // 提前30天
                            noticeRuleSettingAddDTO.setReceiveDateType(ReceiveDateTypeEnum.BEFORE.getValue());
                            NoticeDateSettingVO settingVO = new NoticeDateSettingVO();
                            settingVO.setNumber(30);
                            settingVO.setUnit(3);
                            String jsonDate = JSON.toJSONString(settingVO);
                            noticeRuleSettingAddDTO.setReceiveDateJson(jsonDate);
                        } else if (NoticeConstants.INCREMENT.equals(noticeTypeVO.getCode())) {
                            // 每月第1个工作日9:00
                            noticeRuleSettingAddDTO.setReceiveDateType(ReceiveDateTypeEnum.FIXED.getValue());
                            NoticeDateSettingVO settingVO = new NoticeDateSettingVO();
                            settingVO.setDay(1);
                            settingVO.setTime("09:00:00");
                            String jsonDate = JSON.toJSONString(settingVO);
                            noticeRuleSettingAddDTO.setReceiveDateJson(jsonDate);
                        } else if (NoticeConstants.MEMO_REMIND.equals(noticeTypeVO.getCode())) {
                            // 备忘录只能发给本人
                            noticeRuleSettingAddDTO.setEmpType(EmpType.SELF.getValue());
                            noticeRuleSettingAddDTO.setReceiveDateType(ReceiveDateTypeEnum.RIGHT_NOW.getValue());
                        } else if (NoticeConstants.CONTRACT_EMP_SIGN_OVER.equals(noticeTypeVO.getCode())) {
                            //  合同签署完成只能实时
                            noticeRuleSettingAddDTO.setReceiveDateType(ReceiveDateTypeEnum.RIGHT_NOW.getValue());
                        } else {
                            // 实时
                            noticeRuleSettingAddDTO.setReceiveDateType(ReceiveDateTypeEnum.RIGHT_NOW.getValue());
                        }
                        noticeProviderService.save(noticeRuleSettingAddDTO, tokenUser);
                        count++;
                    }
                }
            }
        }
        long endTime = System.currentTimeMillis();
        log.info("==========用工单位规则设置初始化结束,{}条数据，共用时{}ms==========", count, endTime - startTime);
        return count;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public Integer updateNoticeRuleSetting() {
        int count = 0;
        List<NoticeRuleSettingDO> noticeRuleSettingDOList = noticeRuleSettingService.listAll();
        for (NoticeRuleSettingDO settingDO : noticeRuleSettingDOList) {
            // 只处理json为空的历史数据
            String userIdParam = settingDO.getUserIdParam();
            if (StrKit.isNotEmpty(userIdParam)) {
                continue;
            }
            // 跳过userId不存在的数据
            String userIds = settingDO.getUserIds();
            if (StrKit.isEmpty(userIds)) {
                continue;
            }
            HrNoticeUserIdJsonVO hrNoticeUserIdJsonVO = new HrNoticeUserIdJsonVO();
            hrNoticeUserIdJsonVO.setUserIds(userIds);

            NoticeRuleSettingUpdateDTO updateDTO = new NoticeRuleSettingUpdateDTO();
            updateDTO.setId(settingDO.getId());
            updateDTO.setUserIdParam(JSON.toJSONString(hrNoticeUserIdJsonVO));
            noticeRuleSettingService.updateByIdSelective(updateDTO.to(NoticeRuleSettingDO.class), settingDO.getSiteId(), settingDO.getCreateUserId());
            if (count % 50 == 0) {
                log.info("正在修改第{}条记录", count);
            }
            count++;
        }
        return count;
    }

    @Override
    public List<HrNoticeGroupListVO> jfHomePageNotice(TokenUser tokenUser) {
        List<HrNoticeGroupListVO> result = new ArrayList<>();
        // 甲方端只需要 人事管理/业务审批和合同管理
        NoticeGroupDO personnelGroup = noticeProviderService.selectGroupByName(PERSONNEL_MANAGEMENT);
        NoticeGroupDO businessGroup = noticeProviderService.selectGroupByName(BUSINESS_APPROVAL);
        NoticeGroupDO contractGroup = noticeProviderService.selectGroupByName(CONTRACT_MANAGEMENT);
        // 查询对应的通知类型
        List<NoticeTypeVO> personnelTypeList = noticeProviderService.listTypeByGroupId(HR_SUBJECT_TYPE, personnelGroup.getId());
        List<NoticeTypeVO> businessTypeList = noticeProviderService.listTypeByGroupId(HR_SUBJECT_TYPE, businessGroup.getId());
        List<NoticeTypeVO> contractTypeList = noticeProviderService.listTypeByGroupId(HR_SUBJECT_TYPE, contractGroup.getId());

        // 转换数据类型
        HrNoticeGroupListVO hrPersonnelGroup = personnelGroup.to(HrNoticeGroupListVO.class);
        HrNoticeGroupListVO hrBusinessGroup = businessGroup.to(HrNoticeGroupListVO.class);
        HrNoticeGroupListVO hrContractGroup = contractGroup.to(HrNoticeGroupListVO.class);
        int personnelGroupCount = noticeProviderService
                .selectUserCountByTypeOrGroup(hrPersonnelGroup.getId(), null, false, tokenUser);
        HrNoticeTypeListVO allPersonnel = new HrNoticeTypeListVO();
        allPersonnel.setCount(personnelGroupCount);
        allPersonnel.setName("全部");
        hrPersonnelGroup.setCount(personnelGroupCount);
        int businessGroupCount = noticeProviderService
                .selectUserCountByTypeOrGroup(hrBusinessGroup.getId(), null, false, tokenUser);
        HrNoticeTypeListVO allBusiness = new HrNoticeTypeListVO();
        allBusiness.setCount(businessGroupCount);
        allBusiness.setName("全部");
        hrBusinessGroup.setCount(businessGroupCount);
        int contractGroupCount = noticeProviderService
                .selectUserCountByTypeOrGroup(hrContractGroup.getId(), null, false, tokenUser);
        HrNoticeTypeListVO allContract = new HrNoticeTypeListVO();
        allContract.setCount(contractGroupCount);
        allContract.setName("全部");
        hrContractGroup.setCount(contractGroupCount);
        List<HrNoticeTypeListVO> hrPersonnelTypeList = BeanCopyUtil.beanListCopy(personnelTypeList, HrNoticeTypeListVO.class);
        List<HrNoticeTypeListVO> hrBusinessTypeList = BeanCopyUtil.beanListCopy(businessTypeList, HrNoticeTypeListVO.class);
        List<HrNoticeTypeListVO> hrContractTypeList = BeanCopyUtil.beanListCopy(contractTypeList, HrNoticeTypeListVO.class);
        for (HrNoticeTypeListVO hrNoticeTypeListVO : hrPersonnelTypeList) {
            int typeCount = noticeProviderService.selectUserCountByTypeOrGroup
                    (hrPersonnelGroup.getId(), hrNoticeTypeListVO.getId(), false, tokenUser);
            hrNoticeTypeListVO.setCount(typeCount);
        }
        for (HrNoticeTypeListVO hrNoticeTypeListVO : hrBusinessTypeList) {
            int typeCount = noticeProviderService.selectUserCountByTypeOrGroup
                    (hrBusinessGroup.getId(), hrNoticeTypeListVO.getId(), false, tokenUser);
            hrNoticeTypeListVO.setCount(typeCount);
        }
        for (HrNoticeTypeListVO hrNoticeTypeListVO : hrContractTypeList) {
            int typeCount = noticeProviderService.selectUserCountByTypeOrGroup
                    (hrContractGroup.getId(), hrNoticeTypeListVO.getId(), false, tokenUser);
            hrNoticeTypeListVO.setCount(typeCount);
        }
        // 按照消息通知数量倒叙排序,并且过滤掉消息通知数量为0的类型
        hrPersonnelTypeList = hrPersonnelTypeList.stream()
                .sorted(Comparator.comparing(HrNoticeTypeListVO::getCount).reversed())
                .collect(Collectors.toList());
        hrPersonnelTypeList.add(0, allPersonnel);
        hrBusinessTypeList = hrBusinessTypeList.stream()
                .sorted(Comparator.comparing(HrNoticeTypeListVO::getCount).reversed())
                .collect(Collectors.toList());
        hrBusinessTypeList.add(0, allBusiness);
        hrContractTypeList = hrContractTypeList.stream()
                .sorted(Comparator.comparing(HrNoticeTypeListVO::getCount).reversed())
                .collect(Collectors.toList());
        hrContractTypeList.add(0, allContract);
        hrPersonnelGroup.setNoticeTypeList(hrPersonnelTypeList);
        hrBusinessGroup.setNoticeTypeList(hrBusinessTypeList);
        hrContractGroup.setNoticeTypeList(hrContractTypeList);
        result.add(hrPersonnelGroup);
        result.add(hrBusinessGroup);
        result.add(hrContractGroup);
        return result;
    }

}
